using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ACS.Compiler.Synthes;
using ACS.Compiler.Tables;
using ACS.Compiler.Tables.Modes;
using ACS.Compiler.Tree.Impl;
using ACS.Compiler.Util;

namespace ACS.Compiler.Parser
{
    public class Parser
    {
        private string[] _filesToParse;

        public Parser(string[] filesToParse)
        {
            _filesToParse = filesToParse;
        }

        public void ParseAll()
        {
            try
            {
                foreach (string s in _filesToParse)
                {
                    if (File.Exists(s))
                    {
                        FileParser current = FileParser.InitializeParser(s);
                        current.Parse();
                    }
                    else
                    {
                        Logger.Instance.TraceError("File not found " + s);
                    }
                }

                ProcessProcedures();
                
                ProcessCodeBases();
                
                GenerateModules();

                GenerateDataTypes();

            } catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        private static void GenerateDataTypes()
        {
            foreach (StructMode mode in ModesTable.Instance.Table.Values)
            {
                Formatter.CreateCodeFormatter(mode.Name);
                using (Formatter.Current)
                {
                    StructFormatter formatter = new StructFormatter(mode);
                    formatter.Format();
                }
            }     
        }

        private static void GenerateModules()
        {
            foreach (CodeBase codeBase in CodeTable.Instance.Table.Values)
            {
                Formatter.CreateCodeFormatter(codeBase.Namespace);
                using (Formatter.Current)
                {
                    ModuleFormatter moduleFormater = new ModuleFormatter(codeBase);
                    moduleFormater.Format();
                }
            }
        }

        private static void ProcessCodeBases()
        {
            foreach (KeyValuePair<string, CodeBase> pair in CodeTable.Instance.Table)
            {
                CodeBase codeBase = pair.Value;
                ProcessCode(codeBase.Namespace, codeBase.Module.Code, null);
            }
        }

        private static void ProcessCode(string ns, Block codeBase, DataTable data)
        {
            codeBase.Resolve(ns, data);
        }

        public static Procedure CurrentProcedure = null;

        private static void ProcessProcedures()
        {
            foreach (KeyValuePair<string, Procedure> pair in ProcTable.Instance.Table)
            {
                Procedure proc = pair.Value;
                if (!proc.Standard)
                {
                    CurrentProcedure = proc;
                    ProcessCode(proc.Namespace, proc.CodeBase, proc.ProcData);
                    CurrentProcedure = null;
                }
            }
        }
    }
}
